#include "Console.h"
#include "ConVar.h"
#include "Engine.h"
#include "Render.h"
#include <GL/glfw.h>
#include <iostream>

sb3dConVar	*host_maxfps;
host_parm_t	host;	// host parms

bool sb3dEngine::Run( void )
{	
	if(Init() == false)
		return false;

	host_maxfps = cvars->GetVar( "fps_max", "72", CVAR_ARCHIVE, "host fps upper limit" );
		
	oldtime = glfwGetTime();

	while(bQuit == false)
	{
		newtime = glfwGetTime();
		
		Frame(newtime - oldtime);
		
		oldtime = newtime;
	}
	
	Shutdown();
	
	std::cout << "yoh " << std::endl;
	
	return true;
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window
{
	if (height==0)										// Prevent A Divide By Zero By
	{
		height=1;										// Making Height Equal One
	}

	glViewport(0,0,width,height);						// Reset The Current Viewport

	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
	glLoadIdentity();									// Reset The Projection Matrix

	// Calculate The Aspect Ratio Of The Window
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix
	glLoadIdentity();									// Reset The Modelview Matrix
}

int InitGL()										// All Setup For OpenGL Goes Here
{
	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
	glClearDepth(1.0f);									// Depth Buffer Setup
	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
	return true;										// Initialization Went OK
}

bool sb3dEngine::Init( void )
{
	if(glfwInit() == false)
		return false;
	
	bQuit = false;
	
	cvars = new sb3dConVars();
	
	render = new sb3dRender();
	render->Init();
	
	console = new sb3dConsole();
	console->Init();
	
	ReSizeGLScene(320, 200);					// Set Up Our Perspective GL Screen

	InitGL();

	filteroldtime = 0;
	
	return true;
}

bool sb3dEngine::Shutdown( void )
{
	std::cout << "Terminate 1" << std::endl;
	glfwTerminate();std::cout << "Terminate 2" << std::endl;
	
	delete render;
	delete console;
	delete cvars;

	return true;
}

bool sb3dEngine::Frame( float time )
{
	if(glfwGetKey( GLFW_KEY_ESC ) == GLFW_PRESS)
		bQuit = true;
	
	if(glfwGetKey( GLFW_KEY_F1 ) == GLFW_PRESS)
		console->Toggle();
		
	if(FilterTime( time ))
	{
		render->Render();
		
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
		glLoadIdentity();									// Reset The Current Modelview Matrix
		glTranslatef(-1.5f,0.0f,-6.0f);						// Move Left 1.5 Units And Into The Screen 6.0
		glBegin(GL_TRIANGLES);								// Drawing Using Triangles
		glColor3f(1.0f,0.0f,0.0f);						// Set The Color To Red
		glVertex3f( 0.0f, 1.0f, 0.0f);					// Top
		glColor3f(0.0f,1.0f,0.0f);						// Set The Color To Green
		glVertex3f(-1.0f,-1.0f, 0.0f);					// Bottom Left
		glColor3f(0.0f,0.0f,1.0f);						// Set The Color To Blue
		glVertex3f( 1.0f,-1.0f, 0.0f);					// Bottom Right
		glEnd();											// Finished Drawing The Triangle
	}
	
	render->Render();
	
	glfwSwapBuffers();
	
	return true;
}

bool sb3dEngine::FilterTime( float time )
{
	float		fps;
	
	host.realtime += time;
	
	fps = host_maxfps->value;
	
	if(fps != 0)
	{
		float	minframetime;
		
		fps = bound( MIN_FPS, fps, MAX_FPS );
		
		minframetime = 1.0f / fps;
		
		if(( host.realtime - filteroldtime ) < minframetime )
		{
			return false;		
		}
	}
	
	host.frametime = host.realtime - filteroldtime;
	host.realframetime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
	filteroldtime = host.realtime;
	
	return true;
}